home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / advanced97 / softshadow2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  17.6 KB  |  633 lines

  1.  
  2. /* softshadow2.c - by Simon Hui, 3Dfx Interactive */
  3.  
  4. /* Soft shadows using a shadow texture per polygon.  Based on an algorithm   */
  5. /* described by Paul Heckbert and Michael Herf of CMU; see their web site    */
  6. /* http://www.cs.cmu.edu/ph/shadow.html for details.                         */
  7. /*                                                                           */
  8. /* This program shows two methods of using precomputed, per-polygon textures */
  9. /* to display soft shadows.  The first method is a simplified version of     */
  10. /* Heckbert and Herf's algorithm: for each polygon a texture is created that */
  11. /* encodes the full radiance, including illumination and shadows, of the     */
  12. /* polygon. The texture is created in a preprocessing step by rendering the  */
  13. /* entire scene onto the polygon from the point of view of the light. The    */
  14. /* advantage of this method is that the scene can be rerendered quickly (if  */
  15. /* only the eye moves and the scene is static), since all lighting effects   */
  16. /* have been precomputed and encoded in the texture. This method requires    */
  17. /* GL_RGB textures.                                                          */
  18. /*                                                                           */
  19. /* The second method uses the texture as an occlusion map: the texels        */
  20. /* encode only the amount of occlusion by shadowing objects, not the full    */
  21. /* radiance.  The texture is then used to modulate the lighting of the       */
  22. /* polygon during the rendering pass.  This has the disadvantage of          */
  23. /* requiring OpenGL lighting during scene rendering, but it does retain some */
  24. /* of the benefit of the first method in that all shadow effects are         */
  25. /* precomputed. This method requires GL_LUMINANCE textures.                  */
  26. /*                                                                           */
  27. /* The reason for including the occlusion map method is that some OpenGL     */
  28. /* implementations support GL_RGB textures with low color resolution,        */
  29. /* resulting in noticeable banding when using radiance maps.  However, these */
  30. /* implementations may support a higher color resolution for GL_LUMINANCE    */
  31. /* textures.                                                                 */
  32. /*                                                                           */
  33. /* To use occlusion maps instead of rediance maps, run this program with     */
  34. /* "-o" on the command line.                                                 */
  35.  
  36. #include <GL/glut.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <math.h>
  40.  
  41. #if !defined(GL_VERSION_1_1) && !defined(GL_VERSION_1_2)
  42. #define glBindTexture glBindTextureEXT
  43. #define glCopyTexImage2D glCopyTexImage2DEXT
  44. #endif
  45.  
  46. /* whether to use radiance maps or occlusion maps */
  47. static GLboolean radianceMap = GL_TRUE;
  48.  
  49. static GLint winxsize = 480, winysize = 480;
  50. static GLint texxsize = 128, texysize = 128;
  51.  
  52. /* texture object names */
  53. const GLuint floorTexture = 1;
  54. const GLuint shadowTextures = 2;
  55.  
  56. static GLfloat lightpos[4] = { 70.f, 70.f, -320.f, 1.f };
  57.  
  58. /* number of shadow textures to make and use */
  59. static GLint numShadowTex;
  60.  
  61. /* list of polygons that have shadow textures */
  62. GLfloat pts[][4][3] = {
  63.   /* floor */
  64.   -100.f, -100.f, -320.f,
  65.   -100.f, -100.f, -520.f,
  66.    100.f, -100.f, -320.f,
  67.    100.f, -100.f, -520.f,
  68.  
  69.   /* left wall */
  70.   -100.f, -100.f, -320.f,
  71.   -100.f,  100.f, -320.f,
  72.   -100.f, -100.f, -520.f,
  73.   -100.f,  100.f, -520.f,
  74.  
  75.   /* back wall */
  76.   -100.f, -100.f, -520.f,
  77.   -100.f,  100.f, -520.f,
  78.    100.f, -100.f, -520.f,
  79.    100.f,  100.f, -520.f,
  80.  
  81.   /* right wall */
  82.    100.f, -100.f, -520.f,
  83.    100.f,  100.f, -520.f,
  84.    100.f, -100.f, -320.f,
  85.    100.f,  100.f, -320.f,
  86.  
  87.   /* ceiling */
  88.   -100.f,  100.f, -520.f,
  89.   -100.f,  100.f, -320.f,
  90.    100.f,  100.f, -520.f,
  91.    100.f,  100.f, -320.f,
  92.  
  93.   /* blue panel */
  94.    -60.f,  -40.f, -400.f,
  95.    -60.f,   70.f, -400.f,
  96.    -30.f,  -40.f, -480.f,
  97.    -30.f,   70.f, -480.f,
  98.  
  99.   /* yellow panel */
  100.    -40.f,  -50.f, -400.f,
  101.    -40.f,   50.f, -400.f,
  102.    -10.f,  -50.f, -450.f,
  103.    -10.f,   50.f, -450.f,
  104.  
  105.   /* red panel */
  106.    -20.f,  -60.f, -400.f,
  107.    -20.f,   30.f, -400.f,
  108.     10.f,  -60.f, -420.f,
  109.     10.f,   30.f, -420.f,
  110.  
  111.   /* green panel */
  112.      0.f,  -70.f, -400.f,
  113.      0.f,   10.f, -400.f,
  114.     30.f,  -70.f, -395.f,
  115.     30.f,   10.f, -395.f,
  116. };
  117.  
  118. GLfloat materials[][4] = {
  119.   1.0f, 1.0f, 1.0f, 1.0f, /* floor        */
  120.   1.0f, 1.0f, 1.0f, 1.0f, /* left wall    */
  121.   1.0f, 1.0f, 1.0f, 1.0f, /* back wall    */
  122.   1.0f, 1.0f, 1.0f, 1.0f, /* right wall   */
  123.   1.0f, 1.0f, 1.0f, 1.0f, /* ceiling      */
  124.   0.2f, 0.5f, 1.0f, 1.0f, /* blue panel   */
  125.   1.0f, 0.6f, 0.0f, 1.0f, /* yellow panel */
  126.   1.0f, 0.2f, 0.2f, 1.0f, /* red panel    */
  127.   0.3f, 0.9f, 0.6f, 1.0f, /* green panel  */
  128. };
  129.  
  130. /* some simple vector utility routines */
  131.  
  132. void
  133. vcopy(GLfloat a[3], GLfloat b[3])
  134. {
  135.   b[0] = a[0];
  136.   b[1] = a[1];
  137.   b[2] = a[2];
  138. }
  139.  
  140. void
  141. vnormalize(GLfloat v[3])
  142. {
  143.   float m = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
  144.   v[0] /= m;
  145.   v[1] /= m;
  146.   v[2] /= m;
  147. }
  148.  
  149. void
  150. vadd(GLfloat a[3], GLfloat b[3], GLfloat c[3])
  151. {
  152.   c[0] = a[0] + b[0];
  153.   c[1] = a[1] + b[1];
  154.   c[2] = a[2] + b[2];
  155. }
  156.  
  157. void
  158. vsub(GLfloat a[3], GLfloat b[3], GLfloat c[3])
  159. {
  160.   c[0] = a[0] - b[0];
  161.   c[1] = a[1] - b[1];
  162.   c[2] = a[2] - b[2];
  163. }
  164.  
  165. void
  166. vcross(GLfloat a[3], GLfloat b[3], GLfloat c[3])
  167. {
  168.   c[0] = a[1] * b[2] - a[2] * b[1];
  169.   c[1] = -(a[0] * b[2] - a[2] * b[0]);
  170.   c[2] = a[0] * b[1] - a[1] * b[0];
  171. }
  172.  
  173. float
  174. vdot(GLfloat a[3], GLfloat b[3])
  175. {
  176.   return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]);
  177. }
  178.  
  179. void
  180. findNormal(GLfloat pts[][3], GLfloat normal[3]) {
  181.   GLfloat a[3], b[3];
  182.   
  183.   vsub(pts[1], pts[0], a);
  184.   vsub(pts[2], pts[0], b);
  185.   vcross(b, a, normal);
  186.   vnormalize(normal);
  187. }
  188.  
  189. static GLfloat origin[4] = { 0.f, 0.f, 0.f, 1.f };
  190. static GLfloat black[4] = { 0.f, 0.f, 0.f, 1.f };
  191. static GLfloat ambient[4] = { 0.2f, 0.2f, 0.2f, 1.f };
  192.  
  193. void
  194. make_shadow_texture(int index, GLfloat eyept[3], GLfloat dx, GLfloat dy)
  195. {
  196.   GLfloat xaxis[3], yaxis[3], zaxis[3];
  197.   GLfloat cov[3]; /* center of view */
  198.   GLfloat pte[3]; /* plane to eye */
  199.   GLfloat eye[3];
  200.   GLfloat tmp[3], normal[3], dist;
  201.   GLfloat (*qpts)[3] = pts[index];
  202.   GLfloat left, right, bottom, top;
  203.   GLfloat znear = 10.f, zfar = 600.f;
  204.   GLint n;
  205.  
  206.   /* For simplicity, we don't compute the transformation matrix described */
  207.   /* in Heckbert and Herf's paper.  The transformation and frustum used   */
  208.   /* here is much simpler.                                                */
  209.  
  210.   vcopy(eyept, eye);
  211.   vsub(qpts[1], qpts[0], yaxis);
  212.   vsub(qpts[2], qpts[0], xaxis);
  213.   vcross(yaxis, xaxis, zaxis);
  214.  
  215.   vnormalize(zaxis);
  216.   vnormalize(xaxis); /* x-axis of eye coord system, in object space */
  217.   vnormalize(yaxis); /* y-axis of eye coord system, in object space */
  218.  
  219.   /* jitter the eyepoint */
  220.   eye[0] += xaxis[0] * dx;
  221.   eye[1] += xaxis[1] * dx;
  222.   eye[2] += xaxis[2] * dx;
  223.   eye[0] += yaxis[0] * dy;
  224.   eye[1] += yaxis[1] * dy;
  225.   eye[2] += yaxis[2] * dy;
  226.  
  227.   /* center of view is just eyepoint offset in direction of normal */ 
  228.   vadd(eye, zaxis, cov);
  229.  
  230.   /* set up viewing matrix */
  231.   glPushMatrix();
  232.   glLoadIdentity();
  233.   gluLookAt(eye[0], eye[1], eye[2],
  234.         cov[0], cov[1], cov[2],
  235.         yaxis[0], yaxis[1], yaxis[2]);
  236.  
  237.   /* compute a frustum that just encloses the polygon */
  238.   vsub(qpts[0], eye, tmp); /* from eye to 0th vertex */
  239.   left = vdot(tmp, xaxis);
  240.   vsub(qpts[2], eye, tmp); /* from eye to 2nd vertex */
  241.   right = vdot(tmp, xaxis);
  242.   vsub(qpts[0], eye, tmp); /* from eye to 0th vertex */
  243.   bottom = vdot(tmp, yaxis);
  244.   vsub(qpts[1], eye, tmp); /* from eye to 1st vertex */
  245.   top = vdot(tmp, yaxis);
  246.  
  247.   /* scale the frustum values based on the distance to the polygon */
  248.   vsub(qpts[0], eye, pte);
  249.   dist = fabs(vdot(zaxis, pte));
  250.   left *= (znear/dist);
  251.   right *= (znear/dist);
  252.   bottom *= (znear/dist);
  253.   top *= (znear/dist);
  254.  
  255.   glMatrixMode(GL_PROJECTION);
  256.   glPushMatrix();
  257.   glLoadIdentity();
  258.   glFrustum(left, right, bottom, top, znear, zfar);
  259.   glMatrixMode(GL_MODELVIEW);
  260.  
  261.   if (radianceMap) {
  262.     glEnable(GL_LIGHTING);
  263.     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, materials[index]);
  264.   } else {
  265.     glDisable(GL_LIGHTING);
  266.   }
  267.   glDisable(GL_TEXTURE_2D);
  268.  
  269.   for (n=0; n < numShadowTex; n++) {
  270.     qpts = pts[n];
  271.  
  272.     if (radianceMap) {
  273.       glColor3f(1.f, 1.f, 1.f);
  274.       findNormal(qpts, normal);
  275.       glNormal3fv(normal);
  276.       if (n == index) {
  277.     /* draw this poly with ambient and diffuse lighting */
  278.     glEnable(GL_LIGHT0);
  279.       } else {
  280.     /* draw other polys with ambient lighting only */
  281.     glDisable(GL_LIGHT0);
  282.       }
  283.     } else {
  284.       if (n == index) {
  285.     /* this poly has full intensity, no occlusion */
  286.     glColor3f(1.f, 1.f, 1.f);
  287.       } else {
  288.     /* all other polys just occlude the light */
  289.     glColor3f(0.f, 0.f, 0.f);
  290.       }
  291.     }
  292.     glBegin(GL_TRIANGLE_STRIP);
  293.     glVertex3fv(qpts[0]);
  294.     glVertex3fv(qpts[1]);
  295.     glVertex3fv(qpts[2]);
  296.     glVertex3fv(qpts[3]);
  297.     glEnd();
  298.   }
  299.   glPopMatrix();
  300.   glMatrixMode(GL_PROJECTION);
  301.   glPopMatrix();
  302.   glMatrixMode(GL_MODELVIEW);
  303. }
  304.  
  305. void make_all_shadow_textures(float eye[3], float dx, float dy) {
  306.   GLint texPerRow;
  307.   GLint n;
  308.   GLfloat x, y;
  309.  
  310.   texPerRow = (winxsize / texxsize);
  311.   for (n=0; n < numShadowTex; n++) {
  312.     y = (n / texPerRow) * texysize;
  313.     x = (n % texPerRow) * texxsize;
  314.     glViewport(x, y, texxsize, texysize);
  315.     make_shadow_texture(n, eye, dx, dy);
  316.   }
  317.   glViewport(0, 0, winxsize, winysize);
  318. }
  319.  
  320. void store_all_shadow_textures(void) {
  321.   GLint texPerRow;
  322.   GLint n, x, y;
  323.   GLubyte *texbuf;
  324.   
  325.   texbuf = (GLubyte *) malloc(texxsize * texysize * sizeof(int));
  326.  
  327.   /* how many shadow textures can fit in the window */
  328.   texPerRow = (winxsize / texxsize);
  329.  
  330.   for (n=0; n < numShadowTex; n++) {
  331.     GLenum format;
  332.  
  333.     x = (n % texPerRow) * texxsize;
  334.     y = (n / texPerRow) * texysize;
  335.  
  336.     glBindTexture(GL_TEXTURE_2D, shadowTextures + n);
  337.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  338.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  339.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  340.  
  341.     if (radianceMap) {
  342.       format = GL_RGB;
  343.     } else {
  344.       format = GL_LUMINANCE;
  345.     }
  346.     glCopyTexImage2D(GL_TEXTURE_2D, 0, format, x, y, texxsize, texysize, 0);
  347.   }
  348.   free(texbuf);
  349. }
  350.  
  351. /* menu choices */
  352. enum {
  353.   NOSHADOWS, SOFTSHADOWS, HARDSHADOWS, VIEWTEXTURE, VIEWSCENE, QUIT
  354. };
  355.  
  356. GLint shadowMode = HARDSHADOWS;
  357. GLboolean viewTextures = GL_FALSE;
  358.  
  359. void
  360. redraw(void)
  361. {
  362.   GLint n;
  363.   GLfloat normal[3];
  364.   GLfloat (*qpts)[3];
  365.  
  366.   glPushMatrix();
  367.   glLoadIdentity();
  368.   if (radianceMap && (shadowMode != NOSHADOWS)) {
  369.     glLightfv(GL_LIGHT0, GL_POSITION, origin);
  370.   } else {
  371.     glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  372.   }
  373.   glPopMatrix();
  374.  
  375.   if (shadowMode == SOFTSHADOWS) {
  376.     GLfloat jitterSize;
  377.     GLfloat dx, dy;
  378.     GLint numSteps, i, j;
  379.  
  380.     /* size of the area to jitter the light in */
  381.     jitterSize = 15.0;
  382.  
  383.     /* number of times along x and y to jitter */
  384.     numSteps = 5;
  385.  
  386.     glClear(GL_ACCUM_BUFFER_BIT);
  387.     for (j=0; j < numSteps; j++) {
  388.       for (i=0; i < numSteps; i++) {
  389.  
  390.     /* compute jitter amount, centering the jitter steps around zero */
  391.     dx = (i - (numSteps - 1.0) / 2.0) / (numSteps - 1.0) * jitterSize;
  392.     dy = (j - (numSteps - 1.0) / 2.0) / (numSteps - 1.0) * jitterSize;
  393.  
  394.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  395.     make_all_shadow_textures(lightpos, dx, dy);
  396.     glAccum(GL_ACCUM, 1.0 / (numSteps * numSteps));
  397.     if (viewTextures) {
  398.       glutSwapBuffers();
  399.     }
  400.       }
  401.     }
  402.     glAccum(GL_RETURN, 1.0);
  403.     store_all_shadow_textures();
  404.  
  405.   } else if (shadowMode == HARDSHADOWS) {
  406.  
  407.     /* make shadow textures from just one frame */
  408.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);
  409.     make_all_shadow_textures(lightpos, 0, 0);
  410.     store_all_shadow_textures();
  411.     if (viewTextures) {
  412.       glutSwapBuffers();
  413.     }
  414.   }
  415.   if (viewTextures) {
  416.     glutSwapBuffers();
  417.     return;
  418.   }
  419.  
  420.   glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  421.   glLoadIdentity();
  422.  
  423.   glColor3f(1.f, 1.f, 1.f);
  424.   if (shadowMode == NOSHADOWS) {
  425.     glEnable(GL_LIGHTING);
  426.     glEnable(GL_LIGHT0); 
  427.     glDisable(GL_TEXTURE_2D);
  428.     for (n=0; n < numShadowTex; n++) {
  429.       qpts = pts[n];
  430.       findNormal(qpts, normal);
  431.       glNormal3fv(normal);
  432.       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, materials[n]);
  433.       glBegin(GL_TRIANGLE_STRIP);
  434.       glTexCoord2f(0,0); glVertex3fv(qpts[0]);
  435.       glTexCoord2f(0,1); glVertex3fv(qpts[1]);
  436.       glTexCoord2f(1,0); glVertex3fv(qpts[2]);
  437.       glTexCoord2f(1,1); glVertex3fv(qpts[3]);
  438.       glEnd();
  439.     }
  440.   } else {
  441.     glEnable(GL_TEXTURE_2D);
  442.  
  443.     if (radianceMap) {
  444.       glDisable(GL_LIGHTING);
  445.       for (n=0; n < numShadowTex; n++) {
  446.     qpts = pts[n];
  447.     glBindTexture(GL_TEXTURE_2D, shadowTextures + n);
  448.     glBegin(GL_TRIANGLE_STRIP);
  449.     glTexCoord2f(0,0); glVertex3fv(qpts[0]);
  450.     glTexCoord2f(0,1); glVertex3fv(qpts[1]);
  451.     glTexCoord2f(1,0); glVertex3fv(qpts[2]);
  452.     glTexCoord2f(1,1); glVertex3fv(qpts[3]);
  453.     glEnd();
  454.       }
  455.     } else {
  456.  
  457.       /* Unfortunately, using the texture as an occlusion map requires two */
  458.       /* passes: one in which the occlusion map modulates the diffuse      */
  459.       /* lighting, and one in which the ambient lighting is added in. It's */
  460.       /* incorrect to modulate the ambient lighting, but if the result is  */
  461.       /* acceptable to you, you can include it in the first pass and       */
  462.       /* omit the second pass. */
  463.  
  464.       /* draw only with diffuse light, modulating it with the texture */
  465.       glEnable(GL_LIGHTING);
  466.       glEnable(GL_LIGHT0); 
  467.       glLightModelfv(GL_LIGHT_MODEL_AMBIENT, black);
  468.       for (n=0; n < numShadowTex; n++) {
  469.     qpts = pts[n];
  470.     findNormal(qpts, normal);
  471.     glNormal3fv(normal);
  472.     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, materials[n]);
  473.     glBindTexture(GL_TEXTURE_2D, shadowTextures + n);
  474.     glBegin(GL_TRIANGLE_STRIP);
  475.     glTexCoord2f(0,0); glVertex3fv(qpts[0]);
  476.     glTexCoord2f(0,1); glVertex3fv(qpts[1]);
  477.     glTexCoord2f(1,0); glVertex3fv(qpts[2]);
  478.     glTexCoord2f(1,1); glVertex3fv(qpts[3]);
  479.     glEnd();
  480.       }
  481.  
  482.       /* add in the ambient lighting */
  483.       glDisable(GL_LIGHTING);
  484.       glDisable(GL_TEXTURE_2D);
  485.       glEnable(GL_BLEND);
  486.       glBlendFunc(GL_ONE, GL_ONE);
  487.       glDepthFunc(GL_LEQUAL);
  488.       for (n=0; n < numShadowTex; n++) {
  489.     qpts = pts[n];
  490.     glColor4f(ambient[0] * materials[n][0],
  491.           ambient[1] * materials[n][1],
  492.           ambient[2] * materials[n][2],
  493.           ambient[3] * materials[n][3]);
  494.     glBegin(GL_TRIANGLE_STRIP);
  495.     glTexCoord2f(0,0); glVertex3fv(qpts[0]);
  496.     glTexCoord2f(0,1); glVertex3fv(qpts[1]);
  497.     glTexCoord2f(1,0); glVertex3fv(qpts[2]);
  498.     glTexCoord2f(1,1); glVertex3fv(qpts[3]);
  499.     glEnd();
  500.       }
  501.       /* restore the ambient colors to their defaults */
  502.       glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
  503.     }
  504.   }
  505.  
  506.   /* blend in the checkerboard floor */
  507.   glEnable(GL_BLEND);
  508.   glBlendFunc(GL_ZERO, GL_SRC_COLOR);
  509.   glDepthFunc(GL_LEQUAL);
  510.   glEnable(GL_TEXTURE_2D);
  511.   glBindTexture(GL_TEXTURE_2D, floorTexture);
  512.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, materials[0]);
  513.   glTranslatef(0.0f, 0.05f, 0.0f);
  514.   glColor3f(1.f, 1.f, 1.f);
  515.   glBegin(GL_TRIANGLE_STRIP);
  516.   glNormal3f(0.f, 1.f, 0.f);
  517.   glTexCoord2f(0.f, 0.f); glVertex3fv(pts[0][0]);
  518.   glTexCoord2f(0.f, 1.f); glVertex3fv(pts[0][1]);
  519.   glTexCoord2f(1.f, 0.f); glVertex3fv(pts[0][2]);
  520.   glTexCoord2f(1.f, 1.f); glVertex3fv(pts[0][3]);
  521.   glEnd();
  522.  
  523.   /* undo some state settings that we did above */
  524.   glDisable(GL_BLEND);
  525.   glDisable(GL_TEXTURE_2D);
  526.   glDepthFunc(GL_LESS);
  527.   glTranslatef(0.0f, -0.05f, 0.0f);
  528.  
  529.   glutSwapBuffers();
  530. }
  531.  
  532. void
  533. menu(int mode)
  534. {
  535.   switch (mode) {
  536.   case NOSHADOWS:
  537.   case SOFTSHADOWS:
  538.   case HARDSHADOWS:
  539.     shadowMode = mode;
  540.     break;
  541.   case VIEWTEXTURE:
  542.     viewTextures = GL_TRUE;
  543.     break;
  544.   case VIEWSCENE:
  545.     viewTextures = GL_FALSE;
  546.     break;
  547.   case QUIT:
  548.     exit(0);
  549.   }
  550.   glutPostRedisplay();
  551. }
  552.  
  553. /* Make a checkerboard texture for the floor. */
  554. GLfloat *
  555. make_texture(int maxs, int maxt)
  556. {
  557.   GLint s, t;
  558.   static GLfloat *texture;
  559.  
  560.   texture = (GLfloat *) malloc(maxs * maxt * sizeof(GLfloat));
  561.   for (t = 0; t < maxt; t++) {
  562.     for (s = 0; s < maxs; s++) {
  563.       texture[s + maxs * t] = ((s >> 4) & 0x1) ^ ((t >> 4) & 0x1);
  564.     }
  565.   }
  566.   return texture;
  567. }
  568.  
  569. /* ARGSUSED1 */
  570. void
  571. keyboard(unsigned char key, int x, int y)
  572. {
  573.   if (key == 27)  /* ESC */
  574.     exit(0);
  575. }
  576.  
  577. int
  578. main(int argc, char *argv[])
  579. {
  580.   GLfloat *tex;
  581.   GLint i;
  582.  
  583.   for (i = 1; i < argc; ++i) {
  584.     if (!strcmp("-o", argv[i])) {
  585.       /* use textures as occlusion maps rather than radiance maps */
  586.       radianceMap = GL_FALSE;
  587.     }
  588.   }
  589.  
  590.   glutInit(&argc, argv);
  591.   glutInitWindowSize(winxsize, winysize);
  592.   glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_ACCUM | GLUT_SINGLE);
  593.   (void) glutCreateWindow("soft shadows");
  594.   glutDisplayFunc(redraw);
  595.   glutKeyboardFunc(keyboard);
  596.  
  597.   glutCreateMenu(menu);
  598.   glutAddMenuEntry("No Shadows", NOSHADOWS);
  599.   glutAddMenuEntry("Soft Shadows", SOFTSHADOWS);
  600.   glutAddMenuEntry("Hard Shadows", HARDSHADOWS);
  601.   glutAddMenuEntry("View Textures", VIEWTEXTURE);
  602.   glutAddMenuEntry("View Scene", VIEWSCENE);
  603.   glutAddMenuEntry("Quit", QUIT);
  604.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  605.  
  606.   /* set up perspective projection */
  607.   glMatrixMode(GL_PROJECTION);
  608.   glFrustum(-30., 30., -30., 30., 100., 640.);
  609.   glMatrixMode(GL_MODELVIEW);
  610.  
  611.   /* turn on features */
  612.   glEnable(GL_DEPTH_TEST);
  613.   glEnable(GL_LIGHTING);
  614.   glEnable(GL_LIGHT0);
  615.   glCullFace(GL_BACK);
  616.   glLightfv(GL_LIGHT0, GL_AMBIENT, black);
  617.  
  618.   /* number of shadow textures to make */
  619.   numShadowTex = sizeof(pts) / sizeof(pts[0]);
  620.  
  621.   tex = make_texture(texxsize, texysize);
  622.   glBindTexture(GL_TEXTURE_2D, floorTexture);
  623.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  624.   glTexImage2D(GL_TEXTURE_2D, 0, 1, texxsize, texysize, 0, GL_RED, GL_FLOAT, 
  625.            tex);
  626.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  627.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  628.   free(tex);
  629.  
  630.   glutMainLoop();
  631.   return 0;             /* ANSI C requires main to return int. */
  632. }
  633.